package main

import (
	"fmt"
	"reflect"
)

// 结构体反射

type student struct {
	Name  string `json:"name" ini:"s_name"`
	Score int    `json:"score" ini:"s_score"`
}

// 给student添加两个方法 Study和Sleep（注意首字母大写）
func (s student) Study() string {
	msg := "好好学习，天天向上。"
	fmt.Println(msg)
	return msg
}

func (s student) Sleep() string {
	msg := "好好睡觉。。。"
	fmt.Println(msg)
	return msg
}

// 根据反射获取结构体中方法的函数
func printMethod(x interface{}) {
	t := reflect.TypeOf(x)
	v := reflect.ValueOf(x)
	// 取到结构体中方法数量
	fmt.Println(t.NumMethod())
	for i := 0; i < v.NumMethod(); i++ {
		methodType := v.Method(i).Type()
		fmt.Printf("17_method name:%s\n", t.Method(i).Name)
		fmt.Printf("17_method:%s\n", methodType)
		// 通过反射调用方法传送的参数
		var args = []reflect.Value{}
		v.Method(i).Call(args)
	}
	// 通过方法名获取结构体的方法
	//t.MethodByName("Sleep")
	methodObj := v.MethodByName("Sleep")
	fmt.Println(methodObj.Type())
}

func main() {
	stu1 := student{
		Name:  "nice",
		Score: 90,
	}

	// 通过反射获取结构体中的所有字段信息
	t := reflect.TypeOf(stu1)
	fmt.Printf("name:%v kind:%v\n", t.Name(), t.Kind())
	// 遍历结构体变量的所有字段
	for i := 0; i < t.NumField(); i++ {
		// 根据结构体字段的索引去取字段
		fieldObj := t.Field(i)
		fmt.Printf("name:%v type:%v tag:%v\n", fieldObj.Name, fieldObj.Type, fieldObj.Tag)
		println(fieldObj.Tag.Get("json"))
	}
	// 根据名字取得结构体中的字段
	filed, ok := t.FieldByName("Score")
	if ok {
		fmt.Printf("name:%v type:%v tag:%v\n", filed.Name, filed.Type, filed.Tag)
	}
	printMethod(stu1)
}
